﻿/********
* 
* 
*  Description:
*  Create By Kain at 4/6/2011 3:28:47 PM
*  
*
*  Revision History:
*  Date                  Who                 What
*  
* 
*/

#region

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.ServiceModel.Channels;
using System.ServiceModel;
using System.ServiceModel.Configuration;
using Cherry.Agile.ServiceModel.Interceptor;
using System.Reflection;

#endregion

namespace Cherry.Agile.ServiceModel.Runtime {
    internal static class RuntimeUnity {
        //static IServiceEndpointPolicy __endpointPolicy = DefaultServiceEndpointPolicy.ServiceEndpointPolicy;

        static Type __serviceAttributeType = typeof(System.ServiceModel.ServiceContractAttribute);
        static Lazy<Dictionary<string, string>> _lazy = new Lazy<Dictionary<string, string>>(GetServiceConfigInfo);

        public static List<ServicePackage> GetServicePackages() {
            return GetServicePackages(string.Empty, string.Empty);
        }

        public static List<ServicePackage> GetServicePackages(string baseAddress, string path = null) {
            var packages = new List<ServicePackage>();
            if (string.IsNullOrEmpty(path))
                path = AppDomain.CurrentDomain.BaseDirectory;
            if (string.IsNullOrEmpty(baseAddress))
                baseAddress = Config.RempServiceModelSection.Current.Service.Address;

            var dir = new DirectoryInfo(path);
            if (!dir.Exists)
                return packages;
            var q = dir.GetFiles("*.services.dll").Select(c => new ServicePackage(c.FullName,baseAddress));
            packages.AddRange(q);
            foreach (var item in dir.GetDirectories()) {
                if (item.Name.StartsWith("_"))
                    continue;
                LoadServicePackage(item, packages, baseAddress);
            }
            return packages;
        }

        public static List<IService> GetService(ServicePackage package) {
            var service = new List<IService>();

            var types = Assembly.LoadFile(package.AssemblyFile).GetTypes().Where(c => c.IsClass && !c.IsAbstract);
            foreach (var item in types) {
                LoadType(package, service, item);
            }

            return service;
        }

        public static bool ServiceHasConfig(Type serviceType) {
            return _lazy.Value.ContainsKey(serviceType.FullName);
        }

        static Dictionary<string, string> GetServiceConfigInfo() {
            var serviceConfig = System.Configuration.ConfigurationManager.GetSection("system.serviceModel/services") as ServicesSection;
            var dict = new Dictionary<string, string>();
            if (serviceConfig != null) {
                foreach (System.ServiceModel.Configuration.ServiceElement item in serviceConfig.Services) {
                    dict.Add(item.Name, string.Empty);
                }
            }
            return dict;
        }

        static void LoadServicePackage(DirectoryInfo dir, List<ServicePackage> packages, string baseAddress) {
            var q = dir.GetFiles("*.services.dll").Select(c => new ServicePackage(c.FullName, baseAddress));
            packages.AddRange(q);
            foreach (var item in dir.GetDirectories()) {
                LoadServicePackage(item, packages, baseAddress);
            }
        }

        static void LoadType(ServicePackage package, List<IService> service, Type type) {
            var interfaces = type.GetInterfaces();
            var q = interfaces.Any(c => ValidateServiceInterface(c));
            if (q)
                service.Add(new Service(package.Id, type, package.BaseAddress));
        }

        public static bool ValidateServiceInterface(Type type) {
            if (!type.IsInterface)
                return false;
            return type.GetCustomAttributes(__serviceAttributeType, false).Length > 0;
        }

        public static Binding GetDefeaultBinding() {
            return DefaultEndpointPolicy.EndpointPolicy.DefaultBinding;
        }

        public static void ApplyEndpoints(this ServiceHost host, IService service, string baseAddress = null) {
            foreach (var item in service.ServiceEndpointes) {
                host.AddServiceEndpoint(item);
            }
        }
    }
}
